/**
 * Created by LiYang on 16-9-27 下午2:07.
 *
 */
package com.example.db.support;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import com.example.db.callback.ConnectionCallback;
import com.example.db.callback.CursorCallback;
import com.example.db.callback.PlatformTransaction;
import com.example.db.callback.TransactionCallback;

import java.sql.SQLException;


abstract class DataAccessor extends SQLiteOpenHelper {
    private final String TAG = getClass().getSimpleName();
    private Context context;

    public DataAccessor(Context context, String dbName, CursorFactory factory, int version) {
        super(context, dbName, factory, version);
        this.context = context;
    }

    protected abstract String getTableName();

    protected abstract String getCreateSQL();

    @Override
    public final void onCreate(SQLiteDatabase db) {
    }

    @Override
    public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            deleteTable(db);
        } catch (SQLException e) {
            Log.e(TAG, "", e);
        }
    }

    @Override
    public final void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            deleteTable(db);
        } catch (SQLException e) {
            Log.e(TAG, "", e);
        }
    }

    @Override
    public final void onOpen(SQLiteDatabase db) {
        try {
            if (!isTableExists(db)) {
                db.execSQL(getCreateSQL());
            }
        } catch (SQLException e) {
            Log.e(TAG, "", e);
        }
    }

    protected final boolean deleteTable(SQLiteDatabase db) throws SQLException {
        String sql = "SELECT name FROM sqlite_master WHERE type ='table'";
        String ignored = "android_metadata,sqlite_sequence";
        Cursor cursor = null;
        try {
            cursor = db.rawQuery(sql, null);
            while (cursor.moveToNext()) {
                String name = cursor.getString(0);
                if (ignored.contains(name)) {
                    continue;
                }
                db.execSQL("DROP TABLE IF EXISTS " + name);
            }
        } finally {
            closeSession(null, cursor);
        }
        return false;
    }

    protected final boolean isTableExists(SQLiteDatabase db) throws SQLException {
        String sql = "SELECT COUNT(*) FROM sqlite_master WHERE type ='table' AND name = ?";
        Cursor cursor = null;
        try {
            cursor = db.rawQuery(sql, new String[]{getTableName()});
            if (cursor.moveToNext()) {
                return cursor.getInt(0) > 0;
            }
        } finally {
            closeSession(null, cursor);
        }
        return false;
    }

    protected <T> T execute(ConnectionCallback<T> action) throws SQLException {
        SQLiteDatabase sqlSession = getWritableDatabase();

        try {
            return action.doInConnection(sqlSession);
        } catch (RuntimeException e) {
            Log.e(TAG, "", e);
            throw new SQLException(e);
        } finally {
            closeSession(sqlSession);
        }
    }

    @Deprecated
    public <T> T execute(TransactionCallback<T> action) throws SQLException {
        SQLiteDatabase sqlSession = getWritableDatabase();
        T t;
        try {
            sqlSession.beginTransaction();
            t = action.doInTransaction();
            sqlSession.setTransactionSuccessful();
            return t;
        } catch (RuntimeException e) {
            Log.e(TAG, "", e);
            throw new SQLException(e);
        } finally {
            sqlSession.endTransaction();
            closeSession(sqlSession);
        }
    }

    public void execute(PlatformTransaction action) throws SQLException {
        SQLiteDatabase sqlSession = getWritableDatabase();
        try {
            sqlSession.beginTransaction();
            action.doInTransaction();
            sqlSession.setTransactionSuccessful();
        } catch (RuntimeException e) {
            Log.e(TAG, "", e);
            throw new SQLException(e);
        } finally {
            sqlSession.endTransaction();
            closeSession(sqlSession);
        }
    }

    protected <T> T execute(String sql, String[] args, CursorCallback<T> action)
            throws SQLException {
        SQLiteDatabase sqlSession = getReadableDatabase();
        Cursor cursor = sqlSession.rawQuery(sql, args);
        try {
            return action.doInCursor(cursor);
        } catch (RuntimeException e) {
            Log.e(TAG, "", e);
            throw new SQLException();
        } finally {
            closeSession(sqlSession, cursor);
        }
    }

    protected void closeSession(SQLiteDatabase sdb) throws SQLException {
        closeSession(sdb, null);
    }

    protected void closeSession(SQLiteDatabase sdb, Cursor cursor) throws SQLException {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        if (sdb == null || sdb.inTransaction()) {
            return;
        }
        try {
            sdb.close();
        } catch (RuntimeException e) {
            Log.e(TAG, "", e);
            throw new SQLException(e);
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        close();
    }
}
